/**
 * 
 */
package cn.biplam.front.template.control;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import cn.biplam.common.client.DataFilter;
import cn.biplam.common.client.Operator;
import cn.biplam.common.client.OperatorResult;
import cn.biplam.common.paramters.SysName;
import cn.biplam.common.paramters.TreeParam;
import cn.biplam.common.tools.TOOLS;
import cn.biplam.common.wrapper.ErrorMessage;
import cn.biplam.common.wrapper.KvMap;
import cn.biplam.front.component.data.tree.TreeData;
import cn.biplam.front.component.data.tree.treebase.TreeCallBackNew;
import cn.biplam.front.html.HtmlDiv;
import cn.biplam.front.html.HtmlImage;
import cn.biplam.front.html.HtmlValue;
import cn.biplam.front.html.base.HtmlWindow;
import cn.biplam.front.html.base.Const.Clear_Type;
import cn.biplam.front.html.base.Const.Float_Type;
import cn.biplam.front.html.base.Const.Position_Mode;
import cn.biplam.front.html.base.Const.Visibility_Mode;
import cn.biplam.front.html.base.Const.Window_Event;
import cn.biplam.front.template.base.CheckBox;
import cn.biplam.front.template.base.Text;
import cn.biplam.front.template.control.tree.Icon;
import cn.biplam.front.template.control.tree.PreImage;

/**
 * 树形控件模板
 * @author WangSong 2009-9-29上午10:02:35
 * @version 1.0
 */
public class TreeNew {

	/**树的容器 */
	private HtmlWindow tree;
	/**树的id */
	private String sID;
	/**行为id */
	private String actionId;
	/**父容器id，用来保证树的唯一 */
	private String pcid;
	/**主目录路径 */
	private String sHomeUrl;
	/**treeData容器 */
	private ArrayList<Object[]> alTreeData;
	/**树的操作类 */
	private TreeData treeData;
	/**是否显示复选框 */
	private boolean showCheckBox = false;
	/**是否显示右键菜单 */
	private boolean showRightMenu = false;
	/**右键菜单项 */
	private ArrayList<HtmlWindow> rightMenu;
	/**节点与右键菜单的映射关系 */
	private KvMap<Integer,String[]> nodeRightMapping;
	/**节点和节点辅助信息与右键菜单的映射关系 */
	private KvMap<Integer,String[]> nodeRightItemMapping;
	private KvMap<String,ArrayList<String>> rmItemName; 
	/**节点与右键菜单的映射关系计数器 */
	private int iCount=0;
	/**节点和节点辅助信息与右键菜单的映射关系 */
	private int iCountItem=0;
	/**当前节点是否是跟节点 */
	private boolean isRoot = false;
	/**算出树的节点最大长度 */
	private int maxLength;
	/**回调 */
	private TreeCallBackNew mTreeCallBack;
	/**向下取几级节点信息 */
	private int levelDown;
	/**虚根计数器 */
	private int vrCount;
	/**树索引 */
	private String treeIndex;
	/**展开的节点id */
	private String extendNodeId;
	/**展开的节点id的父亲们 */
	private KvMap<String,String> extentNodeParents;
	/**根节点的父亲，树刷新时使用 */
	private String rootParent;
	/**是否显示加号减号 */
	private boolean showPicExtend = false;
	/**onMouseOver是否已经设置 */
	private boolean onMouseOverIsSet = false;
	/**当前节点容器ID */
	@SuppressWarnings("unused")
	private String nodeContainerId;
	/**自定义参数值 */
	private String customerParam;
	/**是否进行operator过滤*/
	private String isFilterByOperator;
	/** 展开节点点击*/
	private boolean extendClick;
	/**取取树节点的名称、中文名、说明信息的operatorId容器 KvMap<treeIndex,KvMap<operatorType,operatorId>>*/
	private KvMap<String,KvMap<String,String>> nodeTextOperators;
	/** 自定义参数*/
	private String customerParamKey;
	private String customerParamValue;
	/** 节点默认向下展开级别*/
	private KvMap<String,String> defualtLevelDown;
	/** 记录treeData不为空的数目*/
	private int treeDataCount;
	/** dc的参数存储*/
	private KvMap<Integer,String[]> dcParmas;
	/** 单棵树是否显示虚根 true:显示 false:不显示  默认:false*/
	private boolean showVirRoot = false;
	/** 使用的子树,设置过滤后的子树字符串,以"#"分割*/
	private String treeIndexUsed;
	/** 右键菜单参数KvMap<treeIndex,ArrayList<String[key,value]>>*/
	private KvMap<Integer,ArrayList<String[]>> rightMenuParam;
	/** 过滤数据操作id*/
	private String filterOperatorId;
	/** 虚根是否展开,默认不展开*/
	private boolean isVirExtend = false;
	/** 虚根是否展开,默认不展开*/
	private boolean isVirExtendUse = false;
	/** 刷新时操作的树编号*/
	private String treeIndexRefresh;
	/** 树距离左边的距离*/
	private int treeLeftPx = 5; 
	private int levelDownCount = 0;
	private String tableName;
	

	public TreeNew(String pcid,String actionId,ArrayList<Object[]> alTreeData,String sHomeUrl){
		this.sID = pcid+actionId;
		this.pcid = pcid;
		this.tree=new HtmlDiv(pcid+actionId+",-1","tree");
		this.actionId=actionId;
		this.sHomeUrl=sHomeUrl;
		this.alTreeData = alTreeData;
		this.rightMenu = new ArrayList<HtmlWindow>();
		this.nodeRightMapping = new KvMap<Integer,String[]>();
		this.nodeRightItemMapping = new KvMap<Integer, String[]>();
		this.rmItemName = new KvMap<String, ArrayList<String>>();
	}
	
	/**
	 * 设置是否显示复选框
	 * @param showCheckBox true显示
	 */
	public void setCheckBox(boolean showCheckBox){
		this.showCheckBox = showCheckBox;
	}

	/**
	 * 设置树的右键菜单
	 * @param rightMenu  右键菜单
	 * @param objectType  当前右键菜单对应的树的TreeIndex+节点类型
	 * @throws ErrorMessage 
	 */
	public void _setRightMenu(HtmlWindow rightMenu,String ... objectType) throws ErrorMessage{
		if(!this.showRightMenu){
			this.showRightMenu = true;
		}
		this.rightMenu.add(rightMenu);
		for(int i=0;i<objectType.length;i++){
			this.nodeRightMapping.put(iCount,new String[]{objectType[i],rightMenu.getID()});
			this.iCount++;
		}
	}
	
	/**
	 * 设置树的右键菜单项和节点类型和节点描述参数之间的映射关系
	 * @param rightMenuItems 右键菜单项
	 * @param operatorType 节点操作类型
	 * @param nodeDesc 节点右键项显示标志
	 * @throws ErrorMessage 
	 */
	public void _setRightMenuItems(HtmlWindow rightMenuItems,String operatorType,String nodeDesc) throws ErrorMessage{
		this.rightMenu.add(rightMenuItems);
		this.nodeRightItemMapping.put(iCountItem, new String[]{operatorType,rightMenuItems.getID(),nodeDesc});
		ArrayList<String> alRmName = null;
		if(rmItemName.getByKey(operatorType)!=null){
			alRmName = rmItemName.getByKey(operatorType);
		}else{
			alRmName = new ArrayList<String>();
		}
		alRmName.add(rightMenuItems.getID());
		this.rmItemName.put(operatorType, alRmName);
		this.iCountItem++;
	}

	/**
	 * 是否显示加号减号
	 * @param showPicExtend
	 */
	public void showPicExtend(boolean showPicExtend){
		this.showPicExtend = showPicExtend;
	}

	/**
	 * 设置树的当前节点容器id
	 * @param nodeContainerId
	 */
	public void setNodeContainerId(String nodeContainerId){
		this.nodeContainerId = nodeContainerId;
	}

	/**
	 * 设置树的名称固定自定义参数
	 * @param customerParam
	 */
	public void setCustomerParam(String customerParam){
		this.customerParam = customerParam;
	}

	/**
	 * 设置名称不固定自定义参数
	 * @param customerParams
	 */
	public void setCustomerParam(String key ,String value){
		customerParamKey = key;
		customerParamValue = value;
	}

	/**
	 * 是否根据operator过滤
	 * @param isFilterByOperator
	 */
	public void setFilterByOperator(String isFilterByOperator){
		this.isFilterByOperator = isFilterByOperator;
	}

	/**
	 * 设置展开节点的Id
	 * @param extendNodeId 节点id
	 */
	public void setExtendNodeId(String extendNodeId) {
		setExtendNodeId(extendNodeId, false);
	}

	/**
	 * 设置展开节点的Id
	 * @param extendNodeId
	 * @param click 是否点击  true:点击  false:不点击，只标识背景颜色
	 */
	public void setExtendNodeId(String extendNodeId,boolean click) {
		this.extendNodeId = extendNodeId;
		this.extendClick = click;
	}

	/**
	 * 设置取树节点的名称、中文名、说明信息的operatorId
	 * @param nodeTextOperatorIds 通过此id查询树节点的名称、中文名、说明信息
	 * @throws ErrorMessage 
	 */
	public void setNodeTextOperatorId(KvMap<String,KvMap<String,String>> nodeTextOperatorIds) throws ErrorMessage{
		this.nodeTextOperators = nodeTextOperatorIds;
	}

	/**
	 * 设置dctree的默认向下展开级别
	 * @param treeIndex 树编号
	 * @param levelDown 向下展开级别
	 * @throws ErrorMessage 
	 */
	public void setDefaultLevelDown(String treeIndex,String levelDown) throws ErrorMessage{
		if(defualtLevelDown == null){
			defualtLevelDown = new KvMap<String, String>();
		}
		defualtLevelDown.put(treeIndex, levelDown);
	}

	/**
	 * 设置dctree的默认向下展开级别
	 * @param defualtLevelDown
	 * @throws ErrorMessage 
	 */
	public void setDefaultLevelDown(KvMap<String,String> defualtLevelDown) throws ErrorMessage{
		this.defualtLevelDown = defualtLevelDown;
	}
	
	/**
	 * 设置DC的参数，针对父子树和自定义树
	 *   参数存储器为一个字符串数组，存储的参数依次为 
	 *     operatorId(操作id),
	 *     rowid(operator生成sql需要的参数),
	 *     field字符串(父子树使用,operator生成sql中的字段和树的基础字段的映射关系)
	 * dcParams 参数数组
	 * @throws ErrorMessage 
	 */
	public void setDcParams(KvMap<Integer,String[]> dcParams){
		this.dcParmas = dcParams;
	}
	
	/**
	 * 设置是否显示整棵树的虚根,不为空则显示,为空则不显示
	 * @param treeVirRootName
	 */
	public void setShowVirRoot(boolean showVirRoot){
		this.showVirRoot = showVirRoot;
	}
	
	/**
	 * 设置使用的子树索引,设置过滤后的子树字符串,以"#"分割
	 * @param treeIndexUsed 使用的子树索引,以"#"分割
	 */
	public void setUsedTreeIndex(String treeIndexUsed){
		this.treeIndexUsed = treeIndexUsed;
	}
	
	/**
	 * 右键菜单参数KvMap<treeIndex,ArrayList<String[key,value]>>
	 * @param rightMenuParam 右键菜单参数
	 */
	public void setRightMenuParam(KvMap<Integer,ArrayList<String[]>> rightMenuParam){
		this.rightMenuParam = rightMenuParam;
	}
	
	/**
	 * 设置索引树过滤操作id
	 * @param filterOperatorId 过滤操作id
	 */
	public void setFilterOperatorId(String filterOperatorId) {
		this.filterOperatorId = filterOperatorId;
	}
	
	/**
	 * 是否展开虚根,默认不展开
	 * @param isExtend 是否展开虚根 true:展开 false:不展开
	 */
	public void setIsVirRootExtend(boolean isExtend){
		this.isVirExtend = isExtend; 
	}
	
	/**
	 * 设置刷新的子树编号
	 * @param treeIndexRefresh 刷新的子树编号
	 */
	public void setTreeIndexRefresh(String treeIndexRefresh){
		this.treeIndexRefresh = treeIndexRefresh;
	}

	/**
	 * 取树
	 * @return HtmlDiv
	 * @throws ErrorMessage
	 */
	public HtmlWindow get() throws ErrorMessage{
		if(pcid!=null && pcid.length()!=4){
			throw new ErrorMessage("TreeBase.java,pcid length must equal 4:pcid="+pcid);
		}
		//循环alTreeData，判断alTreeData大小是否大于1，大于1则设置虚根，否则直接调用generate(HtmlDiv tree)生成树
		/**设置虚根，
		   判断虚根是否设置，没设置，抛出异常
		   虚根的页面结构为虚根和虚根的子，在虚根的子中调用generate(HtmlDiv tree)，虚根div的ID为cid+order */
		try{
			int alSize = this.alTreeData.size();
			for(int i=0;i<alSize;i++){
				treeData = (TreeData)alTreeData.get(i)[0];
				mTreeCallBack = (TreeCallBackNew)alTreeData.get(i)[1];
				tableName = treeData.getTableName();
				isTreeDatasNull();
				levelDown = treeData.getLevelDown();
				/**设置展开节点信息*/
				getExtendNodeParent();
				if(alSize>1 || showVirRoot){//设置虚根
					//显示虚根时,一级节点显示加减号
					showPicExtend = true;
					setVroot();
				}else{
					generate(tree);
				}
				/**绑定左键容器id，左键目标id、是否显示右键、是否显示checkBox等信息*/
				setTreeParams();
				/**设置树的参数容器*/
				if(isRoot){
					tree.put(getHiddenDiv("hd"+pcid+actionId+treeData.getTreeIndex()));
				}
				
			}
			/**设置整个树的参数*/
			setWholeTreeParam();
			/**设置右键参数*/
			setTreeRightMenu();
			
		}catch(Exception e){
			e.printStackTrace();
		}
		tree.setStyle("padding-left",TOOLS.intToString(treeLeftPx));
		return tree;
	}

	/**
	 * 设置树的参数(以Dc为单元)
	 * @throws ErrorMessage 
	 */
	private void setTreeParams() throws ErrorMessage{
		if(isRoot){
			/**绑定左键容器id（0）、 
			 * 左键行为id（1）、
			 * 是否显示右键（2）、
			 * 是否显示checkBox（3）、
			 * 根节点id（4）、
			 * 左键行为id等信息（5）、
			 * 节点级别（6）、
			 * DcTree参数（7）、
			 * nodeTextOperatorId(8)、
			 * 右键菜单的自定义参数(9)、
			 * 索引树的过滤操作id(10)*/
			//目前左键信息只支持叶子节点的左键信息
			if(treeData.getData()!=null){
				tree.put(new HtmlValue(pcid+actionId+treeIndex,
						mTreeCallBack.getLeftClickTargetIdAll()+","+
						mTreeCallBack.getLeftClickActionIdAll()+","+
						showRightMenu+","+
						showCheckBox+","+
						rootParent+","+
						mTreeCallBack.getLeftClickActionId(treeData.getOperatorType())+","+
						TOOLS.intToString(treeData.getLevelDown())+","+
						getDcTreeParam()+","+
						getTextOperatorId()+","+
						getRightMenuParma()+","+
						filterOperatorId));
			}

		}
	}
	
	/**
	 * 生成dcTree参数字符串,字符串中包括三个参数operatorId、rowid、field字符串,参数之间以","号分隔
	 * @return dcTree参数字符串
	 */
	private String getDcTreeParam(){
		if(dcParmas!=null){
			String[] dcParam = dcParmas.getByKey(TOOLS.stringToInt(treeIndex));
			if(dcParam!=null){
				return dcParam[0]+"#"+dcParam[1]+"#"+dcParam[2];
			}
			
		}
		return null;
	}
	
	/**
	 * 取文本操作ID的字符串
	 * @return 文本操作字符串
	 */
	private String getTextOperatorId(){
		StringBuilder opIds = new StringBuilder();
		if(nodeTextOperators!=null){
			KvMap<String,String> nodeTextOperatorId = nodeTextOperators.getByKey(treeIndex);
			if(nodeTextOperatorId!=null){
				Iterator<Entry<String,String>> it = nodeTextOperatorId.getIterator();
				Entry<String,String> et = null;
				int i=0;
				while(it.hasNext()){
					et = it.next();
					if(i>0){
						opIds.append("<");
						
					}
					opIds.append(et.getKey());
					opIds.append("#");
					opIds.append(et.getValue());
					i++;
				}
			}
		}
		if(opIds.toString()!=null && !"".equals(opIds.toString().trim())){
			return opIds.toString();
		}else{
			return null;
		}
	}
	
	/**
	 * 取右键菜单的自定义参数
	 */
	private String getRightMenuParma(){
		StringBuilder rmps = new StringBuilder();
		if(rightMenuParam!=null){
			ArrayList<String[]> alRp = rightMenuParam.getByKey(TOOLS.stringToInt(treeIndex));
			if(alRp!=null){
				String[] rp = null;
				for(int i=0;i<alRp.size();i++){
					rp = alRp.get(i);
					if(rp != null && rp.length>=2){
						if(i>0){
							rmps.append("<");
							
						}
						rmps.append(rp[0]);
						rmps.append("#");
						rmps.append(rp[1]);
					}
				}
			}
		}
		if(rmps.toString()!=null && !"".equals(rmps.toString().trim())){
			return rmps.toString();
		}else{
			return null;
		}
	}

	/**
	 * 判断是否为空
	 */
	private void isTreeDatasNull(){
		if(!treeData.haveNext()){
			treeDataCount++;
		}
	}

	/**
	 * 设置整颗树的参数
	 * @throws ErrorMessage
	 */
	private void setWholeTreeParam() throws ErrorMessage{
		if(treeDataCount == alTreeData.size()){
			isRoot = true;
		}
		if(isRoot){
			/**展开节点的id和级别*/
			tree.put(new HtmlValue(pcid+actionId+"etId",
					extendNodeId));
			String  ck = "0";
			if(extendClick){
				ck = "1";
			}
			/**展开节点的id和级别*/
			tree.put(new HtmlValue(pcid+actionId+"etck",
					ck));
			/**树的自定义参数 只传value方式，key固定为customerParam*/
			tree.put(new HtmlValue(pcid+actionId+"cuPam",
					customerParam));
			/**树的自定义参数 传key和value*/
			if(customerParamKey!=null){
				tree.put(new HtmlValue(pcid+actionId+customerParamKey,
						customerParamValue));
			}
			tree.put(new HtmlValue(pcid+actionId+"paKs",
					customerParamKey));

			tree.put(new HtmlValue(pcid+actionId+"isFiByOpId",
					isFilterByOperator));
			/**整棵树的虚根,刷新的时候需要传此参数*/
			String showVr = "N";
			if(showVirRoot){
				showVr = "Y";
			}
			tree.put(new HtmlValue(pcid+actionId+"vN",
					showVr));
			/**设置使用的子树索引字符串*/
			tree.put(new HtmlValue(pcid+actionId+"idx",
					treeIndexUsed));
			/**设置一级节点是否显示加减号*/
			String showAdd = "N";
			if(showPicExtend){
				showAdd = "Y";
			}
			tree.put(new HtmlValue(pcid+actionId+"add",
					showAdd));
			/**设置虚根展开*/
			String isVirExt = "N";
			if(isVirExtend){
				isVirExt = "Y";
			}
			tree.put(new HtmlValue(pcid+actionId+"vNExt",
					isVirExt));
			/**设置树的自定义参数*/
			tree.put(getHiddenAll("hd"+pcid+actionId));
		}
	}

	/**
	 * 设置树的右键菜单
	 * @throws ErrorMessage 
	 */
	private void setTreeRightMenu() throws ErrorMessage{
		/**设置右键菜单*/
		if(this.showRightMenu && this.isRoot){
			this._putRightMenu();
			tree.put(new HtmlValue(pcid+actionId+"nodehi",sID+"nodehi",""));
			tree.put(new HtmlValue(pcid+actionId+"level",sID+"level",""));
		}
	}

	/**
	 * 向传入的容器里放入树节点
	 * @param tree	父容器
	 * @throws ErrorMessage 
	 */
	private void generate(HtmlWindow tree) throws ErrorMessage{

		String dID = "";
		/**绘制结点
		 * 	1.if(haveNext()) 移动游标 ，绘制结点（三个容器）*/
		if(treeData.haveNext()){
			treeData.moveNext();
			if(levelDownCount == 0 ){
				levelDownCount = treeData.getNodeLevel();
			}
			if(this.treeData.isRoot()){
				isRoot = true;
				rootParent = treeData.getNodeParent();
			}
			treeIndex = treeData.getTreeIndex();
			//绑定需要展开的节点的脚本
			bindExtendNodeJs();
			onMouseOverIsSet = false;

			char haveLBrother = treeData.haveLBrother();

			dID = getPicId();
			/**当前节点的整体容器,放当前节点和当前节点的子节点*/
			HtmlDiv nodes = new HtmlDiv(dID);
			/**当前节点*/
			HtmlDiv currentNode = this._getNode(dID+",ct");
			/**设置节点大小，不然可能会出现换行*/
			currentNode.setStyleWidth(TOOLS.intToString(maxLength));
			nodes.put(currentNode);
			/**判断是否有儿子
			 * 	如果有儿子,递归(自己的儿子容器)
			 * 判断是否有弟弟
			 * 		如果有弟弟 递归(自己的容器)
			 */
			HtmlDiv childSet = new HtmlDiv(dID+",cset","urs");
			/**所有儿子容器都预置为hidden和绝对定位，这样就不会在客户端存在占位，从而导致出现空白行*/
			/**另：与占位有关的这两个属性，似乎必须在服务器端通过标签传过去，否则Ajx刷新后仍然有占位*/
			if(treeData.getNodeLevel()>=levelDown){
				childSet.setStyle("display", "none");
			}
			if('1' == treeData.haveChild() && (treeData.getNodeLevel()-levelDownCount+1)<levelDown){
				/**当前节点的子节点集合*/
				generate(childSet);
			}
			nodes.put(childSet);
			tree.put(nodes);
			if('1' == haveLBrother){
				this.generate(tree);
			}
		}
	}

	/**
	 * 生成树的当前结点
	 * @return HtmlDiv
	 * @throws ErrorMessage
	 */
	private HtmlDiv _getNode(String id) throws ErrorMessage{

		/**树的当前节点*/
		HtmlDiv node;
		node=new HtmlDiv(id,"uvr");
		HtmlDiv[] aDiv=_createPreImage(
				getPicId(), 
				sHomeUrl,
				treeData.getNodeId(),
				treeData.getNodeLevel(),
				treeData.haveBrother(),
				treeData.haveLBrother(),
				treeData.isLeaf(),
				treeData.getParentSibling());
		for(HtmlDiv ite:aDiv){
			node.put(ite);
		}
		if(showCheckBox){
			if(TOOLS.stringToInt(treeData.getOperatorType())>=3){
				node.put(_getCheckBoxDiv(treeData.getNodeId()));
			}
		}
		node.put(_getNodePic());
		/**判断是否从外部取节点说明,默认显示中文名,中文名为空则显示物理名称*/
		//先从callback中取文本信息
		String text = getText();//节点文本内容
		HtmlWindow textwin = getTextWin(text);
		if(textwin==null){
			node.put(_createTreeText(text));
		}else{
			textwin.setCssID("n");
			_getNodeLength(textwin.getLength());
			node.put(textwin);
		}
		return node;
	}
	
	private HtmlWindow getTextWin(String text) throws ErrorMessage{
		/**先从CallBack中取文本信息*/
		KvMap<String,String> otherParams = new KvMap<String, String>();
		if(customerParamKey!=null){
			otherParams.put(customerParamKey, customerParamValue);
		}
		otherParams.put("cust", customerParam);
		return mTreeCallBack.getText(treeData.getNodeId(), 
				 treeData.getOperatorType(),
				 treeData.getNodeRealId(),
				 text,
				 otherParams);
	}
	
	/**
	 * 取树的文本信息
	 * @return 树的文本信息字符串
	 * @throws ErrorMessage
	 */
	private String getText() throws ErrorMessage{
		/**判断是否从外部取节点说明,默认显示中文名,中文名为空则显示物理名称*/
		KvMap<String,String> nodeTextOperator = null;
		String text = null;
		/**从外部operator取文本信息*/
		if(nodeTextOperators!=null){
			nodeTextOperator = nodeTextOperators.getByKey(treeData.getTreeIndex());
		}
		if(nodeTextOperator!=null && nodeTextOperator.getByKey(treeData.getOperatorType())!=null){
			text = getNodeText(nodeTextOperator.getByKey(treeData.getOperatorType()),
					treeData.getNodeRealId());
		}
		/**从索引表取文本信息*/
		if(TOOLS.StringIsEmpty(text)){
			if(!TOOLS.StringIsEmpty(treeData.getNodeName())){
				text = treeData.getNodeName();
			}else{
				text = treeData.getNodeId();
			}
		}
		return text;
	}

	/**
	 * 取树的图片信息
	 * @param sID  树id
	 * @param sHomeUrl 项目的主目录
	 * @param sNodeID  节点id
	 * @param iLevel   节点级别
	 * @param cHasGG  是否有哥哥
	 * @param cHasDD  是否有弟弟
	 * @param cHasChild  是否有儿子
	 * @param aParentHasDD  父亲是否有弟弟
	 * @return  HtmlDiv[]
	 * @throws ErrorMessage
	 */
	private HtmlDiv[] _createPreImage(String sID,String sHomeUrl,String sNodeID,int iLevel,
			char cHasGG,char cHasDD,char cHasChild,char[] aParentHasDD) throws ErrorMessage{
		HtmlDiv[] aDiv=new PreImage(sID, 
									sHomeUrl, 
									sNodeID, 
									iLevel, 
									cHasGG, 
									cHasDD, 
									cHasChild, 
									aParentHasDD,
									this.levelDown,
									showPicExtend,
									this.mTreeCallBack.getPlusMinus()).getAll();
		return aDiv;
	}

	/**
	 * 取树的节点说明信息
	 * @param text  树的说明信息
	 * @return HtmlWindow
	 * @throws ErrorMessage
	 */
	private HtmlWindow _createTreeText(String text) throws ErrorMessage{
		/**拼接树的节点说明的id,目前以tree_id,node_id的方式拼接*/
		HtmlWindow mText = new Text(text,this.getPicId()+"text").get();
		mText.setCssID("n");
		/**右键菜单的设置，根据节点的类别设置*/
		bindRightMenu(mText);
		/**树的左键*/	
		bindLeftOnclick(mText,text);
		/**加隐藏表单，用于右键treeS ajx的pr()和左键ajx的p()*/
		mText.put(new HtmlValue(getPicId()+"text"+"r",
				treeData.getNodeId()+","+
				treeData.getNodeRealId()+","+
				treeData.getNodeLevel()+","+
				treeData.getTreeIndex()));
		_getNodeLength(mText.getLength());
		return mText;
	}
	
	/**
	 * 取数的复选框信息
	 * @param nodeId  复选框代表的对象id
	 * @return HtmlDiv
	 * @throws ErrorMessage
	 */
	private HtmlDiv _getCheckBoxDiv(String nodeId) throws ErrorMessage{
		HtmlDiv mDiv = new CheckBox(sID+"ckb",nodeId,sHomeUrl).get();
		return mDiv;
	}

	/**
	 * 将右键菜单放入tree的容器中
	 * @throws ErrorMessage 
	 */
	private void _putRightMenu() throws ErrorMessage{
		for(int i=0;i<rightMenu.size();i++){
			tree.put(rightMenu.get(i));
		}
		this._generateRightMenuJsData();

	}

	/**
	 * 动态生成右键菜单的js需要的input数据
	 * @throws ErrorMessage 
	 */
	private void _generateRightMenuJsData() throws ErrorMessage{
		/**设置右键菜单与节点类型的映射关系*/
		for(int i=0;i<nodeRightMapping.size();i++){
			tree.put(new HtmlValue(pcid+actionId+nodeRightMapping.getByKey(i)[0],
					pcid+actionId+nodeRightMapping.getByKey(i)[0],
					nodeRightMapping.getByKey(i)[1]));
		}
		/**设置右键菜单项与节点类型的映射关系*/
		StringBuilder ocMapping = new StringBuilder();
		ArrayList<String> rmItemNameArr = null;
		for(int i=0;i<nodeRightItemMapping.size();i++){
			
			rmItemNameArr = this.rmItemName.getByKey(nodeRightItemMapping.getByKey(i)[0]);
			if(rmItemNameArr!=null && rmItemNameArr.size()>0){
				tree.put(new HtmlValue(pcid+actionId+nodeRightItemMapping.getByKey(i)[0]+"it",
						pcid+actionId+nodeRightItemMapping.getByKey(i)[0]+"it",
						arrayListToString(rmItemNameArr)));
			}
			if(i>0){
				ocMapping.append(",");
			}
			ocMapping.append(nodeRightItemMapping.getByKey(i)[0]);
			ocMapping.append(":");
			ocMapping.append(nodeRightItemMapping.getByKey(i)[1]);
			ocMapping.append(":");
			ocMapping.append(nodeRightItemMapping.getByKey(i)[2]);
			
		}
		/**右键菜单区别项*/
		tree.put(new HtmlValue(pcid+actionId+"rm",pcid+actionId+"rm",ocMapping.toString()));
	}
	
	private String arrayListToString(ArrayList<String> rmItemNameArr){
		StringBuilder om = new StringBuilder();
		int i=0;
		for(String itemName:rmItemNameArr){
			if(i>0){
				om.append(",");
			}
			om.append(itemName);
			i++;
		}
		return om.toString();
	}

	/**
	 * 设置树的节点的长度
	 * @throws ErrorMessage 
	 */
	private int _getNodeLength(int textLen) throws ErrorMessage{
		if(textLen==0){
			throw new ErrorMessage("Text Length equal 0.");
		}
		int base=this.treeData.getNodeLevel()+1;
		if(this.showCheckBox){
			base = base+1;
		}
		int length = 18*base+TOOLS.getPxLength(textLen)+6;
		if(length>this.maxLength){
			this.maxLength=length;
		}
		return length;
	}

	/**
	 * 设置图标
	 * @throws ErrorMessage 
	 */
	private HtmlWindow _getNodePic() throws ErrorMessage{

		//取图片的名字
		String picName = this.mTreeCallBack.getNodePic(this.treeData.getOperatorType(),treeData.getNodeType(),
				this.isLeaf());
		//取图片显示页面
		Icon mIcon = new Icon(this.sHomeUrl,picName,this.treeData.getNodeLevel(),this.levelDown);
		HtmlWindow img = mIcon.get(this.getPicId(), this.treeData.isLeaf(), this.treeData.isRoot());
		String leftScript = this.mTreeCallBack.getPicScript(this.treeData.getOperatorType(),
				this.isLeaf(), 
				this.getTreeId(), 
				this.treeData.getNodeLevel(), 
				this.levelDown,
				this.showPicExtend);
		if(leftScript!=null && !"".equals(leftScript)){
			img.bind(Window_Event.OnClick,leftScript);
		}
		return img;
	}

	/**
	 * 设置树的虚根
	 * @throws ErrorMessage
	 */
	private void setVroot() throws ErrorMessage{
		if(this.treeData.getVNodeName()==null || "".equals(this.treeData.getVNodeName().trim())){
			this.showPicExtend = false;
			generate(tree);
		}else{
			//树刷新时只展开操作的子树虚根
			_setVirExtend();
			
			String vrID = this.pcid+this.actionId+","+this.vrCount;
			//虚根整体的Div
			HtmlWindow vr = new HtmlDiv(vrID);
			vr.setClear(Clear_Type.Both);
			//虚根显示的Div
			HtmlWindow vrNode = new HtmlDiv(vrID+",ct");
			this.setVrootNode(vrNode,vrID+",ct");
			vrNode.setStyle("cursor", "hand");
			//虚根儿子的Div
			HtmlWindow vrChild = new HtmlDiv(vrID+",cset");
			this.generate(vrChild);
			if(isVirExtendUse){
				//虚根展开
				vrChild.setVisibility(Visibility_Mode.Inherit);
				vrChild.setStyle("position", "static");
			}else{
				//虚根不展开
				vrChild.setVisibility(Visibility_Mode.Hidden);
				vrChild.setPositionMode(Position_Mode.Absolute);
			}
			//vrChild.setMarginLeft("18");

			vrNode.bind(Window_Event.OnClick,"vrp('"+vrID+"')");
			vrNode.bind(Window_Event.OnmouseOver,"onNode(this)");
			//vrNode.bind("vrp('"+vrID+"');");
			vr.put(vrNode);
			vr.put(vrChild);


			tree.put(vr);
			this.vrCount++;
		}
	}

	/**
	 * 虚根设置信息
	 * @param vrNode
	 * @throws ErrorMessage 
	 */
	private void setVrootNode(HtmlWindow vrNode,String vnId) throws ErrorMessage{
		HtmlWindow pic = new HtmlDiv();
		pic.setFloat(Float_Type.Left);
		pic.setStyleWidth("18");
		pic.setStyleHeight("18");
		this.getVrPic(pic,vnId);
		vrNode.put(pic);
		HtmlWindow vrText = new Text(this.treeData.getVNodeName()).get();
		vrNode.put(vrText);
	}

	/**
	 * 获取图片显示页面
	 * @param ReportID
	 * @param isLeaf
	 * @param isRoot
	 * @throws ErrorMessage
	 */
	private void getVrPic(HtmlWindow pic,String vrPicID) throws ErrorMessage{
		HtmlWindow open = this._getIcon(vrPicID+"s",this.sHomeUrl+"/images/o"+mTreeCallBack.getVirNodePic());//+o minus5.gif
		HtmlWindow uopen = this._getIcon(vrPicID+"u",this.sHomeUrl+"/images/"+mTreeCallBack.getVirNodePic());//plus5.gif
		if(isVirExtendUse){
			uopen.setVisibility(Visibility_Mode.Hidden);
		}else{
			open.setVisibility(Visibility_Mode.Hidden);
		}
		
		pic.put(uopen);
		pic.put(open);
	}

	/**
	 * 创建一个用于图片切换的内置Div
	 */
	private HtmlWindow _getIcon(String ID,String imageUrl) throws ErrorMessage{
		HtmlWindow div = new HtmlDiv(ID);
		div.setPositionMode(Position_Mode.Absolute);
		HtmlWindow mImage=new HtmlImage(imageUrl,"tinorm");
		div.put(mImage);
		return div;
	}

	/**
	 * 树的右键绑定
	 * @param mText
	 * @throws ErrorMessage
	 */
	private void bindRightMenu(HtmlWindow mText) throws ErrorMessage{
		String rightKey =this.treeData.getTreeIndex()+this.treeData.getOperatorType();
		if(this.showRightMenu){
			mText.bind(Window_Event.OnContextMenu,"showRMNew(this,'"+rightKey+"'); return false;");
			this._bindTextOnMouseOver(mText);
		}
	}

	/**
	 * 树的左键脚本绑定
	 * @param mText
	 * @throws ErrorMessage 
	 */
	private void bindLeftOnclick(HtmlWindow mText,String text) throws ErrorMessage{
		//取绑定脚本
		String leftScript = this.mTreeCallBack.getLeftClickScript(this.pcid,
																  this.treeData.getOperatorType(),
																  this.isLeaf(), 
																  this.getTreeId(), 
																  this.treeData.getNodeLevel(), 
																  this.levelDown,
																  this.showPicExtend,
																  this.showCheckBox,
																  this.tableName,
																  this.actionId,
																  text);
		if(leftScript!=null && !"".equals(leftScript)){
			mText.bind(Window_Event.OnClick,leftScript);
			this._bindTextOnMouseOver(mText);
		}
	}

	/**
	 * 设置onMouseOver
	 * @param mText
	 * @throws ErrorMessage
	 */
	private void _bindTextOnMouseOver(HtmlWindow mText) throws ErrorMessage{
		if(!this.onMouseOverIsSet){
			mText.bind(Window_Event.OnmouseOver,mTreeCallBack.getNodeOnMouseOver(this.treeData.getOperatorType()));
			this.onMouseOverIsSet = true;
		}
	}

	/**
	 * 判断是否是叶子节点
	 * @return boolean
	 * @throws ErrorMessage
	 */
	private boolean isLeaf() throws ErrorMessage{
		boolean isLeaf = false;
		if(this.treeData.isLeaf()=='0'){
			isLeaf = true;
		}
		return isLeaf;
	}

	/**
	 * 拼接树的节点ID：pcid+actionid,nodeId,nodeType,operatorType,nodeLevel,是否有哥哥,是否有弟弟,realId,父亲们是否有弟弟
	 * @return 树的ID
	 * @throws ErrorMessage 
	 */
	private String getTreeId() throws ErrorMessage{
		return this.getPicId();
	}

	/**
	 * 拼接树节点图片的ID：pcid+actionid,nodeId,nodeType,operatorType,nodeLevel,是否有哥哥,是否有弟弟,realId,父亲们是否有弟弟
	 * @return 图片ID
	 * @throws ErrorMessage
	 */
	private String getPicId() throws ErrorMessage{
		StringBuilder sb = new StringBuilder();

		sb.append(pcid+this.actionId+",");
		sb.append(treeData.getNodeId()+",");
		sb.append(treeData.getTreeIndex()+",");
		sb.append(treeData.getOperatorType()+",");
		sb.append(treeData.getNodeLevel()+",");
		sb.append(treeData.haveBrother()+",");
		sb.append(treeData.haveLBrother()+",");
		sb.append(treeData.getNodeRealId()+",");
		sb.append(getParentsHaveLBrother()+",");
		sb.append(treeData.getNodeType());

		return sb.toString();
	}

	/**
	 * 取父亲们是否有弟弟
	 * @return 字符串，以"_"分割
	 */
	private String getParentsHaveLBrother(){
		String parentsHaveLBrother = "";
		char[] c = this.treeData.getParentSibling();
		for(int i=0;i<c.length;i++){
			if(i==0){
				parentsHaveLBrother = String.valueOf(c[i]);
			}else{
				if(String.valueOf(c[i])!=null){
					parentsHaveLBrother = parentsHaveLBrother +"_"+String.valueOf(c[i]);
				}
			}
		}
		return parentsHaveLBrother;
	}

	/**
	 * 初始化需要展开节点的父亲们
	 * @throws ErrorMessage 
	 */
	private void getExtendNodeParent() throws ErrorMessage{
		if(!TOOLS.StringIsEmpty(this.extendNodeId)){
			this.extentNodeParents = this.treeData.getExtendNodeAllParent(extendNodeId);
			this.tree.bind("$('"+pcid+actionId+"etId').value='"+extendNodeId+"';");
		}
	}

	/**
	 * 设置树的某一节点展开脚本绑定
	 * @throws ErrorMessage 
	 */
	private void bindExtendNodeJs() throws ErrorMessage{
		if(treeData!=null){
			int dfld = 1;
			if(defualtLevelDown!=null && defualtLevelDown.getByKey(treeIndex)!=null){
				dfld = TOOLS.stringToInt(defualtLevelDown.getByKey(treeIndex));
			}
			//如果设置了需要展开的节点id，则判断当前节点是否是 需展开的节点的父亲之一，是则绑定脚本。
			if(this.extentNodeParents!=null && 
					this.extentNodeParents.getByKey(this.treeData.getNodeId())!=null){
				String funtion = "tk('"+this.getPicId()+",c','"+this.pcid+this.actionId+"');";
				if(treeData.getNodeLevel()==1 && !showPicExtend){
					funtion = "tkr('"+this.getPicId()+",s','"+this.pcid+this.actionId+"');";
				}
				if(dfld>1){
					if((treeData.getNodeLevel()-levelDownCount+1)>=dfld){
						this.tree.bind(funtion);
					}
				}else{
					this.tree.bind(funtion);
				}
			}
			if(treeData.getNodeId()!=null && treeData.getNodeId().equals(extendNodeId)){
				if(dfld>1){
					if((treeData.getNodeLevel()-levelDownCount+1)>dfld){
						if(extendClick){
							tree.bind("$('"+getPicId()+"text').click();");
						}else{
							tree.bind("changeBg($('"+getPicId()+"text'));");
						}
					}
				}else{
					if(extendClick){
						tree.bind("$('"+getPicId()+"text').click();");
					}else{
						tree.bind("changeBg($('"+getPicId()+"text'));");
					}
				}
				
			}
		}
	}

	/**
	 * 返回树的节点的最大长度
	 * @return int
	 */
	public int getNodeMaxLength(){
		return this.maxLength+this.treeLeftPx;
	}

	/**
	 * 根据设置的operatorId取节点的说明信息
	 *   <li>结果集列约定索引 0:ID 1:名称
	 * @param operatorId 操作节点id
	 * @param ID 操作表的主键id
	 * @return String 需要的节点信息字符串
	 * @throws ErrorMessage 
	 */
	private String getNodeText(String operatorId,String ID) throws ErrorMessage{
		OperatorResult or = Operator.get(operatorId, SysName.SysUser, new DataFilter(ID));
		if(TOOLS.exist(or)){
			return or.getValue(1);
		}
		return null;
	}
	
	/**
	 * 设置树的隐藏参数
	 * @param hiddenId 隐藏容器id
	 * @return 隐藏参数div
	 * @throws ErrorMessage
	 */
	private HtmlWindow getHiddenDiv(String hiddenId) throws ErrorMessage{
		HtmlWindow hp = new HtmlDiv(hiddenId);
		hp.setPositionMode(Position_Mode.Absolute);
		hp.setVisibility(Visibility_Mode.Hidden);
		hp.put(new HtmlValue(null,hiddenId+","+TreeParam.NODE_ID,""));
		hp.put(new HtmlValue(null,hiddenId+","+TreeParam.TREE_INDEX,""));
		hp.put(new HtmlValue(null,hiddenId+","+TreeParam.OPERATOR_TYPE,""));
		hp.put(new HtmlValue(null,hiddenId+","+TreeParam.NODE_REAL_ID,""));
		hp.put(new HtmlValue(null,hiddenId+","+TreeParam.TREE_PCID,""));
		hp.put(new HtmlValue(null,hiddenId+","+TreeParam.TABLE_NAME,""));
		hp.put(new HtmlValue(null,hiddenId+","+TreeParam.TREE_AID,""));
		hp.put(new HtmlValue(null,hiddenId+","+TreeParam.NODE_NAME,""));
		
		int treeIndex = TOOLS.stringToInt(treeData.getTreeIndex());
		/**设置自定义参数*/
		if(rightMenuParam!=null && rightMenuParam.getByKey(treeIndex)!=null){
			ArrayList<String[]> alParam = rightMenuParam.getByKey(treeIndex);
			if(alParam!=null){
				for(int i=0;i<alParam.size();i++){
					hp.put(new HtmlValue(null,hiddenId+","+alParam.get(i)[0],alParam.get(i)[1]));
				}
			}
		}
		return hp;
	}
	
	/**
	 * 设置树的隐藏参数
	 * @param hiddenId 隐藏容器id
	 * @return 隐藏参数div
	 * @throws ErrorMessage
	 */
	private HtmlValue getHiddenAll(String hiddenId) throws ErrorMessage{
		
		int treeIndex = 0;
		ArrayList<String[]> alParam = null;
		
		/**设置自定义参数*/
		StringBuilder allp = new StringBuilder();
		int j=0;
		if(rightMenuParam!=null){
			for(Map.Entry<Integer,ArrayList<String[]>> it:rightMenuParam){
				treeIndex = it.getKey();
				alParam = it.getValue();
				if(alParam!=null){
					for(int i=0;i<alParam.size();i++){
						if(j>0){
							allp.append("~");
						}
						allp.append(treeIndex);
						allp.append(":");
						allp.append(alParam.get(i)[0]);
						allp.append(":");
						allp.append(alParam.get(i)[1]);
						j++;
					}
				}
			}
		}
		return new HtmlValue("a"+hiddenId,null,allp.toString());
	}
	
	/**
	 * 设置虚根显示
	 */
	private void _setVirExtend(){
		if(treeIndexRefresh!=null && treeIndexRefresh.equals(treeData.getTreeIndex())){
			isVirExtendUse = true;
		}else{
			isVirExtendUse = isVirExtend;
		}
	}

	/**
	 * 树的节点索引id
	 */
	public enum TreeID_Index{
		/** 节点id */
		NodeID (1),
		/** 节点类型 */
		NodeType (2),
		/** 节点操作类型 */
		OperatorType (3),
		/** 节点级别 */
		NodeLevel (4),
		/** 是否有哥哥 */
		HaveBrother (5),
		/** 是否有弟弟*/
		HaveLBrother(6),
		/** 真实id*/
		NodeRealId(7),
		/** 父亲是否有弟弟*/
		ParentsHaveLBrother(8),
		/** 节点描述*/
		NodeDesc(9);
		private int value;
		private TreeID_Index(int value){this.value=value;}
		public int toInt() {return value;}
	}
}
